package com.xxl.job.admin.core.thread;

import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.model.XxlJobLogDetail;
import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
import com.xxl.job.admin.core.util.LogXssTagUtil;
import com.xxl.job.admin.core.util.TenantContextUtil;
import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.LogParam;
import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.biz.model.ReturnT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 调度成功的日志入库
 *
 * @author chenlinqing
 * @description:
 * @date: 2025/8/7 18:16
 */
public class JobLogDetail2DbHelper {
    private static Logger logger = LoggerFactory.getLogger(JobLogDetail2DbHelper.class);

    private static JobLogDetail2DbHelper instance = new JobLogDetail2DbHelper();

    public static JobLogDetail2DbHelper getInstance() {
        return instance;
    }


    private Thread logDetailThread;
    private volatile boolean toStop = false;

    public void start() {
        logDetailThread = new Thread(new Runnable() {

            @Override
            public void run() {
                while (!toStop && XxlJobAdminConfig.getAdminConfig().isLogToDb()) {
                    long startTime = System.currentTimeMillis();
                    Connection conn = null;
                    Boolean connAutoCommit = null;
                    PreparedStatement preparedStatement = null;
                    try {

                        conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection();
                        connAutoCommit = conn.getAutoCommit();
                        conn.setAutoCommit(false);

                        preparedStatement = conn.prepareStatement("select * from xxl_job_lock where lock_name = 'log_detail_lock' for update");
                        preparedStatement.execute();

                        TenantContextUtil.setTenantId(null);
                        List<Long> logIdList = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDetailDao().getJobLogFinishTrigger2WriteExecutorLog();
                        if (!CollectionUtils.isEmpty(logIdList)) {
                            for (Long logId : logIdList) {
                                XxlJobLogDetail logDetail = new XxlJobLogDetail();
                                logDetail.setLogId(logId);
                                XxlJobLog jobLog = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(logId);
                                if (jobLog == null) {
                                    // 保存日志，但记录为失败
                                    logDetail.setLogDetail("logId为空，无法获取日志");
                                    XxlJobAdminConfig.getAdminConfig().getXxlJobLogDetailDao().insert(logDetail);
                                }
                                TenantContextUtil.setTenantId(jobLog.getTenantId());
                                ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
                                ReturnT<LogResult> logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), logId, 1));

                                // is end
                                if (logResult.getContent() != null && jobLog.getHandleCode() > 0) {
                                    if (logResult.getContent() != null && StringUtils.hasText(logResult.getContent().getLogContent())) {
                                        String newLogContent = LogXssTagUtil.filter(logResult.getContent().getLogContent());
                                        logResult.getContent().setLogContent(newLogContent);
                                    }
                                    //保存日志
                                    logDetail.setLogDetail(logResult.getContent().getLogContent());
                                    XxlJobAdminConfig.getAdminConfig().getXxlJobLogDetailDao().insert(logDetail);

                                }
                            }
                        }
                        long processTimeCost = System.currentTimeMillis() - startTime;
                        TimeUnit.MILLISECONDS.sleep(600000 - processTimeCost);
                    } catch (Exception e) {
                        if(!toStop){
                            logger.error(">>>>>>>>>>> xxl-job, JobLogDetail2DbHelper error:{}", e);
                        }
                    } finally {
                        // commit
                        if (conn != null) {
                            try {
                                conn.commit();
                            } catch (Throwable e) {
                                logger.error(e.getMessage(), e);
                            }
                            try {
                                conn.setAutoCommit(connAutoCommit);
                            } catch (Throwable e) {
                                logger.error(e.getMessage(), e);
                            }
                            try {
                                conn.close();
                            } catch (Throwable e) {
                                logger.error(e.getMessage(), e);
                            }
                        }

                        // close PreparedStatement
                        if (null != preparedStatement) {
                            try {
                                preparedStatement.close();
                            } catch (Throwable e) {
                                logger.error(e.getMessage(), e);
                            }
                        }
                    }

                }
                logger.info(">>>>>>>>>>> xxl-job, job log detail thread stop");

            }
        });
        logDetailThread.setDaemon(true);
        logDetailThread.setName("xxl-job, admin JobLogDetail2DbHelper");
        logDetailThread.start();
    }

    public void toStop() {
        toStop = true;
        // interrupt and wait
        logDetailThread.interrupt();
        try {
            logDetailThread.join();
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }
    }

}
